﻿using System;
using System.Collections.Generic;
using System.Text;
using GraphAPI;
using GraphAPI.Model;
using System.Windows.Forms;
using System.Drawing;

namespace Coloring
{
	public class Coloring : IAlgorithm
	{
		public Coloring()
		{
		}

		#region IAlgorithm Members

		public string Name
		{
			get { return "Раскраска"; }
		}

		public string Description
		{
			get { return "Раскраска графа минимальным количесвом цветов."; }
		}

		public string Category
		{
			get { return ""; }
		}

		internal struct VertexInfo
		{
			public int Pow;
			public int Index;
		}

		private int VertexInfoComparer(VertexInfo x, VertexInfo y)
		{
			return y.Pow - x.Pow;
		}

		internal struct HSVColor
		{
			public short Hue;
			public float Saturation, Value;
			public Color toColor()
			{
				Color ret = new Color();

				float R = 0, G = 0, B = 0, hTemp = 0;
				int i = 0;

				if (Saturation == 0.0f)
					R = G = B = Value;
				else
				{
					if (Hue == 360)
						hTemp = 0.0f;
					else
						hTemp = Hue;
					hTemp /= 60.0f;
					i = (int)hTemp % 6;
					int f=(int)(hTemp - Math.Abs(hTemp));          //-- fractional part of h 
					float p, q, t;
					p = Value * (1.0f - Saturation);
					q = Value * (1.0f - (Saturation * f));
					t = Value * (1.0f - (Saturation * (1.0f - f)));

					switch (i)
					{
						case 0:
							{
								R = Value;
								G = t;
								B = p;
							}
							break;
						case 1:
							{
								R = q;
								G = Value;
								B = p;
							}
							break;
						case 2:
							{
								R = p;
								G = Value;
								B = t;
							}
							break;
						case 3:
							{
								R = p;
								G = q;
								B = Value;
							}
							break;
						case 4:
							{
								R = t;
								G = p;
								B = Value;
							}
							break;
						case 5:
							{
								R = Value;
								G = p;
								B = q;
							}
							break;
					}
				}
/* 
  return rgb(R*255, G*255, B*255) 
end HSVtoRGB*/
				ret = Color.FromArgb((int)(R * 255), (int)(G * 255), (int)(B * 255));

				return ret;
			}
		}

		public Control Use(Graph graph)
		{
			Graph coloredGraph = new Graph(graph);

			// Подготовка
			VertexInfo[] vi = new VertexInfo[coloredGraph.EntityCount];
			for (int i = 0; i < coloredGraph.EntityCount; i++)
			{
				vi[i].Index = i;
				for (int iRel = 0; iRel < coloredGraph.RelationCount; iRel++)
				{
					if (coloredGraph.IntendMatrix[i, iRel] != 0)
						vi[i].Pow++;
				}
			}
			Array.Sort<VertexInfo>(vi, VertexInfoComparer);

			int[] colors = new int[coloredGraph.EntityCount];
			for (int i = 0; i < coloredGraph.EntityCount; i++)
			{
				colors[i] = -1;
			}

			int color = 0;
			int colored = 0;
			// Цикл назначения цветовых групп
			while (colored < coloredGraph.EntityCount)
			{
				foreach (VertexInfo v in vi)
				{
					if (colors[v.Index] > -1)
						continue;

					bool coloredNeighboors = false;
					for (int iN = 0; iN < coloredGraph.EntityCount; iN++)
					{
						if (coloredGraph.RelationMatrix[v.Index, iN] && colors[iN] == color)
						{
							coloredNeighboors = true;
							break;
						}
					}

					if (coloredNeighboors)
						continue;

					colors[v.Index] = color;
					colored++;
				}

				color++;
			}

			Random rand = new Random();

			HSVColor[] colorArray = new HSVColor[color];
			for (int i = 0; i < color; i++)
			{
				/*byte R, G, B;
				R = (byte)rand.Next(0, 16777216);
				G = (byte)rand.Next(0, 16777216 / colored - R);
				B = (byte)rand.Next(0, 16777216 / colored - R - G);*/

				colorArray[i] = new HSVColor();
				if ((colorArray[i].Hue = (short)(360 / color * i)) == 0)
					colorArray[i].Hue = (short)(360 / (4 * color));

				if((colorArray[i].Saturation = 1.0f / color * i) ==0)
					colorArray[i].Saturation = 1.0f / (color*2);

				if((colorArray[i].Value = 1.0f / color * i) ==0)
					colorArray[i].Value = 1.0f / (color);
			}

			for (int i = 0; i < coloredGraph.EntityCount; i++)
			{
				coloredGraph.Entitys[i].ColorMark = colorArray[colors[i]].toColor();
			}

			ColoringCtrl panel = new ColoringCtrl();
			panel.graphPanel.Graph = coloredGraph;
			panel.graphPanel.ReadOnly = true;

			for (int i = 0; i < colorArray.Length; i++)
			{
				Panel legendElement = new Panel();
				legendElement.BackColor = colorArray[i].toColor();
				legendElement.Width = panel.legendPanel.Width / 2;
				legendElement.Height = 20;

				Point pos = new Point(5, 2* i * legendElement.Height);
				legendElement.Location = pos;
				legendElement.BorderStyle = BorderStyle.FixedSingle;

				Label legElmntLabel = new Label();
				legElmntLabel.Text = "Группа " + i.ToString();
				pos.X += panel.legendPanel.Width / 2;
				legElmntLabel.Height = legendElement.Height;
				legElmntLabel.Width = legendElement.Width;
				legElmntLabel.TextAlign = ContentAlignment.MiddleCenter;
				legElmntLabel.Location = pos;

				panel.legendPanel.Controls.Add(legendElement);
				panel.legendPanel.Controls.Add(legElmntLabel);
			}

			return panel;
		}

		#endregion
	}
}
